﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Security.Cryptography;
using System.IO;
using vstream;
#if UNITY_EDITOR
using UnityEditor;


public class VexAssetExport
{
    //支持资源类型
    static Dictionary<System.Type, string> types = new Dictionary<System.Type, string> {
        {typeof(GameObject), "model"},
        {typeof(Material), "material"}
    };

    const string EXPORT_TEMP_PATH = "/temp";

    [MenuItem("资产导出/设置颜色空间为为线形")]
    static void SetColorSpaceToLinear()
    {
        if (PlayerSettings.colorSpace != ColorSpace.Linear)
        {
            PlayerSettings.colorSpace = ColorSpace.Linear;
        }
    }

    [MenuItem("资产导出/解锁场景中的资产(readable)")]
    public static void UnlockReadable()
    {
        Scene scene = SceneManager.GetActiveScene();
        var objs = scene.GetRootGameObjects();
        List<GameObject> gameObjects = new List<GameObject>();
        foreach (var child in objs)
            FindSubObjects(child, gameObjects);
        HashSet<string> isReadIds = new HashSet<string>();
        foreach (var obj in gameObjects)
        {
            MeshFilter filter = obj.GetComponent<MeshFilter>();
            if (filter != null)
            {
                Mesh mesh = filter.sharedMesh;
                string path = AssetDatabase.GetAssetPath(mesh);
                if (path != string.Empty && !isReadIds.Contains(path))
                {
                    ModelImporter importer = ModelImporter.GetAtPath(path) as ModelImporter;
                    if (!importer.isReadable)
                    {
                        Debug.Log("resource unlock:" + path);
                        importer.isReadable = true;
                        importer.SaveAndReimport();
                        isReadIds.Add(path);
                    }
                }
            }
            MeshRenderer renderer = obj.GetComponent<MeshRenderer>();
            if (renderer != null)
            {
                Material[] materials = renderer.sharedMaterials;
                foreach (var mat in materials)
                {
                    var props = MaterialEditor.GetMaterialProperties(new Material[] { mat });
                    foreach (var prop in props)
                    {
                        if (prop.type == MaterialProperty.PropType.Texture)
                        {
                            Texture texture = prop.textureValue;
                            if (texture != null)
                            {
                                string path = AssetDatabase.GetAssetPath(texture);
                                if (path != string.Empty && !isReadIds.Contains(path))
                                {
                                    TextureImporter importer = TextureImporter.GetAtPath(path) as TextureImporter;
                                    if (!importer.isReadable)
                                    {
                                        Debug.Log("resource unlock:" + path);
                                        importer.isReadable = true;
                                        importer.SaveAndReimport();
                                        isReadIds.Add(path);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    [MenuItem("资产导出/解锁资源中所有资产(readable)")]
    static void UnlockProjectAllResources() 
    {
        string[] paths = AssetDatabase.GetAllAssetPaths();
        foreach (var path in paths)
        {
            AssetImporter importer = AssetImporter.GetAtPath(path);
            if (importer is ModelImporter)
            {
                var temp = importer as ModelImporter;
                if (!temp.isReadable)
                {
                    temp.isReadable = true;
                    importer.SaveAndReimport();
                }
            }
            else if (importer is TextureImporter)
            {
                var temp = importer as TextureImporter;
                if (!temp.isReadable)
                {
                    temp.isReadable = true;
                    importer.SaveAndReimport();
                }
            }
        }
    }

    [MenuItem("资产导出/将选中的资产进行导出")]
    static void ExportAssets()
    {
        if (!CheckColorSpaceIsLinear())
            return;
        try
        {
            //获取保存路径
            string savePath = EditorUtility.SaveFilePanel("Save Resource", "", "New Resource", "vasset");
            if (savePath == string.Empty)
                return;
            Object[] sels = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets);
            List<System.Object[]> storge = new List<object[]>();
            for (int i = 0; i < sels.Length; i++)
            {
                Object obj = sels[i];
                //处理文件夹
                if (obj is DefaultAsset)
                {
                    string dirPath = AssetDatabase.GetAssetPath(obj);
                    FindObject(dirPath, storge);
                }
                else
                {
                    Compress(obj, storge);
                }
            }
            //导出
            BufOut bo = new BufOut();
            bo.writeObject(storge.Count);
            bo.writeObject(storge);
            var exportData = bo.Finish();
            File.WriteAllBytes(savePath, exportData);
        }
        finally 
        {
            string tmp = GetRootPath(EXPORT_TEMP_PATH);
            new DirectoryInfo(tmp).Delete(true);
        }
    }

    /// <summary>
    /// 遍历查找资源
    /// </summary>
    /// <param name="path"></param>
    /// <param name="storge"></param>
    static void FindObject(string path, List<System.Object[]> storge) 
    {
        if (!Directory.Exists(path))
            return;
        string[] children = Directory.GetFiles(path);
        foreach (var child in children) 
        {
            if (Directory.Exists(child))
            {
                FindObject(child, storge);
            }
            else 
            {
                string ext = Path.GetExtension(child);
                if (ext == ".meta")
                    continue;
                var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(child);
                if (obj != null && !(obj is DefaultAsset)) 
                {
                    Compress(obj, storge);
                }
            }
        }
    }

    /// <summary>
    /// 压缩存储
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="storage"></param>
    static void Compress(Object obj, List<System.Object[]> storage) 
    {
        var clz = obj.GetType();
        if (types.ContainsKey(clz)) 
        {
            string type = types[clz];
            //缩略图
            var imgData = GetObjectThumbnail(obj);
            //bundle
            string path = AssetDatabase.GetAssetPath(obj);
            var bundleData = ExportAssetBundleData(path);
            storage.Add(new System.Object[] {
                obj.name,
                path,
                type,
                imgData,
                bundleData
            });
            Debug.Log("Compress:" + path);
        }
    }

    #region tool
    static byte[] ExportAssetBundleData(string path)
    {
        string uuid = GetMd5(path);
        AssetBundleBuild[] build = new AssetBundleBuild[1];
        build[0].assetNames = new string[] { path };
        build[0].assetBundleName = uuid;
        //生成导出目录
        string export = GetRootPath(EXPORT_TEMP_PATH);
        string readPath = export + "/" + uuid;
        string folder = "Assets" + EXPORT_TEMP_PATH;
        BuildPipeline.BuildAssetBundles(folder, build, BuildAssetBundleOptions.None, BuildTarget.WebGL);
        var assetData = File.ReadAllBytes(readPath);
        return assetData;
    }

    static byte[] GetObjectThumbnail(Object obj) 
    {
        var texture = AssetPreview.GetMiniThumbnail(obj);
        texture = DeCompress(texture);
        var imgData = texture.EncodeToJPG();
        return imgData;
    }

    static Texture2D DeCompress(Texture source)
    {
        RenderTexture renderTex = RenderTexture.GetTemporary(
                    source.width,
                    source.height,
                    0,
                    RenderTextureFormat.Default,
                    RenderTextureReadWrite.Linear);
        Graphics.Blit(source, renderTex);
        RenderTexture previous = RenderTexture.active;
        RenderTexture.active = renderTex;

        TextureFormat format = TextureFormat.RGBA32;
        //一般unity对资源库中的贴图都做了压缩处理非透明为DXT1，透明为DXT5，若不是则读取原始format进行转换
        if (source is Texture2D)
        {
            format = ((Texture2D)source).format;
            if (format == TextureFormat.DXT1)
            {
                format = TextureFormat.RGB24;
            }
            if (format == TextureFormat.DXT5)
            {
                format = TextureFormat.RGBA32;
            }
        }
        Texture2D readableText = new Texture2D(source.width, source.height, format, false);
        readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
        readableText.Apply();
        RenderTexture.active = previous;
        RenderTexture.ReleaseTemporary(renderTex);
        return readableText;
    }

    static string GetMd5(string src)
    {
        var srcData = System.Text.Encoding.Unicode.GetBytes(src);
        MD5 md5 = new MD5CryptoServiceProvider();
        byte[] targetData = md5.ComputeHash(srcData);
        string byte2String = null;
        for (int i = 0; i < targetData.Length; i++)
        {
            byte2String += targetData[i].ToString("X2");
        }
        return byte2String;
    }

    static string GetRootPath(string path, bool create = true) 
    {
        string result = Application.dataPath + path;
        if (!Directory.Exists(result) && create)
            Directory.CreateDirectory(result);
        return result;
    }

    static void FindSubObjects(GameObject target, List<GameObject> list)
    {
        list.Add(target);
        for (int i = 0; i < target.transform.childCount; i++)
        {
            FindSubObjects(target.transform.GetChild(i).gameObject, list);
        }
    }

    static bool CheckColorSpaceIsLinear() 
    {
        if (PlayerSettings.colorSpace != ColorSpace.Linear) 
        {
            Debug.Log("请先设置颜色空间为Linear");
            return false;
        }
        return true;
    }
    #endregion
}
#endif
